home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / EDIT_UTL / TRIVED09 / TRIVED.PAS < prev   
Pascal/Delphi Source File  |  1995-04-23  |  60KB  |  2,964 lines

  1. program trived;  {trivial editor}
  2.  
  3. {
  4. Russell Schulz - russell@alpha3.ersys.edmonton.ab.ca (950423)
  5.  
  6. Copyright 1995 Russell Schulz
  7.  
  8. this code is not in the Public Domain
  9.  
  10. permission is granted to use these routines in any application regardless
  11. of commercial status as long as the author of these routines assumes no
  12. liability for any damages whatsoever for any reason.  have fun.
  13. }
  14.  
  15. {create a .TPM file for tp4}
  16.  
  17. {$ifdef VER40}
  18. {$T+} 
  19. {$endif}
  20.  
  21. uses dos,crt,genericf;
  22.  
  23. {
  24.  
  25. KNOWN SHORTCOMINGS (but don't let them scare you away)
  26.  
  27. unable to search regexp's
  28. unable to search-and-replace, among many other : commands
  29. takes minimal advantage of terminal capabilities (possible feature)
  30. ansi/vt100 hardwired in for cursor movement, clear screen, clear to end of line
  31. implements only trivial subset of vi
  32. doesn't implement modifiers (eg. dw, y3+, c$)
  33. doesn't handle arrow keys from console or terminal
  34. doesn't handle tabs in files very well
  35. doesn't handle long lines very well
  36.  
  37. uses some vi keystrokes
  38.   possible feature :-)
  39.  
  40.  
  41. CREDITS:
  42.  
  43. Bill Joy, for the (incredibly more powerful) vi editor
  44.  
  45. }
  46.  
  47. {$define debug}
  48. {$undef debug}
  49.  
  50. {$define smallmemory}
  51. {$undef smallmemory}
  52.  
  53. {   stack,minimum heap,maximum heap  }
  54.  
  55. {$ifdef smallmemory}
  56. {$M 8192,10240,24000}
  57. {$else}
  58. {$M 8192,10240,655360}
  59. {$endif}
  60.  
  61. const
  62.   editorname='trived';
  63.   editorversion='0.9';
  64.  
  65.   rotates='\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-\|/-/|\-';
  66.  
  67.   minlpp=8;
  68.   maxlpp=50;
  69.  
  70.   mincols=32;
  71.   maxcols=132;
  72.  
  73.   yespreserve=true;
  74.   nopreserve=false;
  75.  
  76. {needed for serio}
  77.  
  78.   eightbitclean=true;
  79.   readlnecho=true;
  80.  
  81.  
  82. type
  83.   ptr=^node;
  84.   node=record
  85.          str: string;
  86.          next: ptr;
  87. {$ifdef debug}
  88.          seq: integer;
  89. {$endif}
  90.        end;
  91.  
  92. var
  93.   lpp: integer;
  94.   cols: integer;
  95.  
  96.   editinglpp: integer;
  97.  
  98. {$ifdef debug}
  99.   debug: boolean;
  100.   highseq: integer;
  101.   history: string;
  102. {$endif}
  103.  
  104.   shadow: integer;
  105.   changed: boolean;
  106.  
  107.   head: ptr;
  108.   afterhead: node;
  109.   tail: ptr;
  110.   unused: ptr;
  111.  
  112.   numlines: integer;
  113.   port: integer;
  114.   console: boolean;
  115.   filename: string;
  116.   thefile: text;
  117.   quitout: boolean;
  118.   topline: integer;
  119.   currline: integer;
  120.   currptr: ptr;
  121.   currcol: integer;
  122.   counter: integer;
  123.   bufferedstring: string;
  124.   keeptocol: integer;
  125.  
  126.   alwayshelp: boolean;
  127.  
  128.   directory: string;
  129.   trusted: boolean;
  130.  
  131.   oldtextattr: byte;
  132.  
  133.   cmdline: string;
  134.   searchstring: string;
  135.  
  136.   alternatefilename: string;
  137.  
  138.   undoline: integer;
  139.   undostring: string;
  140.   undomaybestring: string;
  141.  
  142. {below here are for serio}
  143.  
  144.   minutestorun: integer;
  145.   idleminutes: integer;
  146.   minstart: integer;
  147.   minlastinput: integer;
  148.   didtimeout: boolean;
  149.  
  150.   lowcolor: byte;
  151.   highcolor: byte;
  152.  
  153. {$define pgdnbecomesgt}
  154. {$define timeout}
  155.  
  156. {$I serio.pas}
  157.  
  158. procedure refreshall; forward;
  159.  
  160. procedure usage;
  161.  
  162. begin
  163.   writeln('usage: ',editorname,' [options] filename');
  164.   writeln;
  165.   writeln('options:');
  166.   writeln('  -h/--help for permanent on-screen help');
  167.   writeln('  -m/--minutes number-of-minutes-to-run');
  168.   writeln('  -d/--dir directory from where user may read files');
  169.   writeln('  -p/--port 1 for COM1, 2 for COM2');
  170.   writeln('  -f/--fossil-port 0 for COM1, 1 for COM2');
  171.   writeln('  -t/--trusted modem user may read all files');
  172.   writeln('  -l/--lines number-of-lines');
  173.   writeln('  -c/--columns number-of-columns');
  174.   writeln('  --colors low-color,high-color (e.g., 3,15)');
  175.   writeln;
  176.   writeln('  -f and -p are exactly the same except for');
  177.   writeln('    -f starting at 0 and -p starting at 1');
  178.   writeln;
  179.   writeln('eg: (from waffle) ',editorname,' -p %d -m %O filename');
  180.   writeln;
  181. {$ifdef debug}
  182.   writeln('debug: use ^A to turn on debugging info, ^Q to quit+dump');
  183.   writeln;
  184. {$endif}
  185.   writeln('russell@alpha3.ersys.edmonton.ab.ca (930228)');
  186.   halt(1);
  187. end;
  188.  
  189. procedure restorecolors;
  190.  
  191. begin
  192.   if console then
  193.     begin
  194.       xgotoxy(1,lpp);
  195.       textattr := oldtextattr;
  196.       writeln;  {so it uses these new (original) colors for sure}
  197.     end;
  198. end;
  199.  
  200. {$ifdef debug}
  201. procedure restorecurs; forward;
  202.  
  203. procedure debugmsg(s: string);
  204.  
  205. begin
  206.   if debug then
  207.     begin
  208.       gotoxy(40, 4);write(' -------------------------------- ');
  209.       gotoxy(40, 5);write('|                                |');
  210.       gotoxy(40, 6);write(' -------------------------------- ');
  211.       gotoxy(42,5);
  212.       write(s);
  213.       restorecurs;
  214.     end;
  215. end;
  216.  
  217. procedure debugdie(s: string);
  218.  
  219. var
  220.   aptr: ptr;
  221.   linesprinted: integer;
  222.  
  223. begin
  224.   restorecolors;
  225.  
  226.   if s<>'' then
  227.     clrscr;
  228.  
  229.   writeln(s);
  230.   writeln('history=',history);
  231.   writeln;
  232.  
  233.   aptr := currptr;
  234.   if aptr=nil then
  235.     writeln('currptr=nil')
  236.   else if aptr^.seq>highseq then
  237.     writeln('currptr is invalid (sequence=',aptr^.seq,')')
  238.   else
  239.     writeln('currptr=',aptr^.seq:3,' ',copy(aptr^.str,1,40));
  240.   writeln;
  241.  
  242.   linesprinted := 0;
  243.   aptr := afterhead.next;
  244.   while aptr<>nil do
  245.     begin
  246.       write('/',aptr^.seq:3,' ',copy(aptr^.str,1,10):10,' ');
  247.       aptr := aptr^.next;
  248.       inc(linesprinted);
  249.       if linesprinted>numlines then
  250.         begin
  251.           writeln;
  252.           writeln('saw ',linesprinted,' lines already -- too many');
  253.           aptr := nil;
  254.         end;
  255.     end;
  256.  
  257.   halt(1);
  258. end;
  259. {$endif}
  260.  
  261.  
  262. { --- misc routines --- }
  263.  
  264.  
  265. procedure donothing;
  266.  
  267. begin
  268. end;
  269.  
  270. function mayuse(var somefn: string): boolean;
  271.  
  272. var
  273.   problem: boolean;
  274.  
  275. begin
  276.   problem := true;
  277.  
  278.   if trusted then
  279.     problem := illegalfn(somefn)
  280.   else
  281.     begin
  282.       problem := suspiciousfn(somefn);
  283.       if not problem then
  284.         somefn := directory+'\'+somefn;
  285.     end;
  286.  
  287.   mayuse := not problem;
  288. end;
  289.  
  290. function fixfn(fn: string): string;
  291.  
  292. begin
  293.   if (fn='#') and (alternatefilename<>'') then
  294.     fixfn := alternatefilename
  295.   else
  296.     fixfn := fn;
  297. end;
  298.  
  299.  
  300. { --- undo --- }
  301.  
  302.  
  303. procedure itmightchange;
  304.  
  305. begin
  306.   undomaybestring := currptr^.str;
  307. end;
  308.  
  309. procedure ithaschanged;
  310.  
  311. begin
  312.   undoline := currline;
  313.   undostring := undomaybestring;
  314.   changed := true;
  315. end;
  316.  
  317.  
  318. { --- linked list stuff --- }
  319.  
  320.  
  321. function ptrafter(prevptr: ptr): ptr;
  322.  
  323. var
  324.   result: ptr;
  325.  
  326. begin
  327.   result := nil;
  328.   if unused<>nil then
  329.     begin
  330.  
  331. {$ifdef debug}
  332.       debugmsg('got new ptr from unused');
  333. {$endif}
  334.  
  335.       result := unused;
  336.       unused := result^.next;
  337.     end
  338.   else if maxavail>1024 then
  339.     begin
  340.  
  341. {$ifdef debug}
  342.       debugmsg('got new ptr from heap');
  343. {$endif}
  344.  
  345.       new(result);
  346.     end;
  347.  
  348.   if result<>nil then
  349.     begin
  350.       result^.str := '';
  351.       result^.next := nil;
  352. {$ifdef debug}
  353.       inc(highseq);
  354.       result^.seq := highseq;
  355. {$endif}
  356.  
  357.       if afterhead.next=nil then
  358.         begin
  359.  
  360. {$ifdef debug}
  361.           debugmsg('result is only node');
  362. {$endif}
  363.  
  364.           afterhead.next := result;
  365.           tail := result;
  366.         end
  367.       else
  368.         begin
  369.  
  370. {$ifdef debug}
  371.           if debug then
  372.             if prevptr=nil then
  373.               debugmsg('error: ptrafter(nil)');
  374. {$endif}
  375.  
  376.           if prevptr=tail then
  377.             begin
  378.  
  379. {$ifdef debug}
  380.               debugmsg('result is new tail');
  381. {$endif}
  382.  
  383.               tail := result;
  384.             end;
  385.  
  386.           result^.next := prevptr^.next;
  387.           prevptr^.next := result;
  388.         end;
  389.     end;
  390.  
  391.   ptrafter := result;
  392. end;
  393.  
  394. function prev(aptr: ptr): ptr;
  395.  
  396. var
  397.   result: ptr;
  398.   chase: ptr;
  399.  
  400. begin
  401.   result := nil;
  402.  
  403.   chase := head;
  404.   while chase<>nil do
  405.     begin
  406.       if chase^.next=aptr then
  407.         begin
  408.           result := chase;
  409.           chase := nil;
  410.         end
  411.       else
  412.         chase := chase^.next;
  413.     end;
  414.  
  415. {$ifdef debug}
  416.   if debug then
  417.     if result=nil then
  418.       debugdie('error: prev('+aptr^.str+')=nil');
  419. {$endif}
  420.  
  421.   prev := result;
  422. end;
  423.  
  424. procedure deleteptr(aptr: ptr);
  425.  
  426. var
  427.   prevptr: ptr;
  428.  
  429. begin
  430.   prevptr := prev(aptr);
  431.  
  432. {fix up tail if need be}
  433.  
  434.   if aptr=tail then
  435.     tail := prevptr;
  436.  
  437. {fix up main list}
  438.  
  439.   prevptr^.next := aptr^.next;
  440.  
  441. {add it to unused list}
  442.  
  443.   aptr^.next := unused;
  444.   unused := aptr;
  445. end;
  446.  
  447. function nthptr(n: integer): ptr;
  448.  
  449. var
  450.   result: ptr;
  451.   i: integer;
  452.   steps: integer;
  453.  
  454. begin
  455.   result := nil;
  456.  
  457.   if n=numlines then
  458.     begin
  459.       steps := 0;
  460.       result := tail;
  461.     end
  462.   else if n>=currline then
  463.     begin
  464.       steps := n-currline;
  465.       result := currptr;
  466.     end
  467.   else
  468.     begin
  469.       steps := n-1;
  470.       result := afterhead.next;
  471.     end;
  472.  
  473.   for i := 1 to steps do
  474.     if result<>nil then
  475.       result := result^.next;
  476.  
  477.   nthptr := result;
  478. end;
  479.  
  480. procedure setcurrlineptr(lineno: integer);
  481.  
  482. begin
  483.   currptr := nthptr(lineno);
  484.   currline := lineno;
  485. end;
  486.  
  487.  
  488. { --- i/o stuff --- }
  489.  
  490.  
  491. procedure wastekey;
  492.  
  493. var
  494.   wastec: char;
  495.  
  496. begin
  497.   wastec := xreadkey;
  498. end;
  499.  
  500. procedure warn(warning: string);
  501.  
  502. begin
  503.   xgotoxy(1,lpp-1);
  504.   xclreol;
  505.   xgotoxy(1,lpp);
  506.   xclreol;
  507.   xwritess(warning,' - press any key ');
  508.   wastekey;
  509.   refreshall;
  510. end;
  511.  
  512. function currlength: integer;
  513.  
  514. begin
  515.   if currptr=nil then
  516.     currlength := 0
  517.   else
  518.     currlength := length(currptr^.str);
  519. end;
  520.  
  521. procedure reposcurs;
  522.  
  523. begin
  524.   xgotoxy(currcol,currline-topline+1);
  525. end;
  526.  
  527. procedure restorecurs;
  528.  
  529. begin
  530.   currcol := min(currlength,keeptocol);
  531.  
  532. {}{} {need to scroll, not just restrict, but this allows the file to be edited}
  533.   if currcol>cols then
  534.     currcol := cols;
  535.  
  536.   if currcol=0 then
  537.     currcol := 1;
  538.  
  539.   reposcurs;
  540. end;
  541.  
  542. procedure setstatusline(s: string);
  543.  
  544. begin
  545.   xclreolxy(1,lpp);
  546.   xwritehighlights(s);
  547.   restorecurs;
  548. end;
  549.  
  550. procedure displayfileinfo;
  551.  
  552. var
  553.   statusline: string;
  554.   perthrough: integer;
  555.  
  556. begin
  557.   statusline := '<'+filename+'>';
  558.  
  559.   if changed then
  560.     statusline := statusline+' [modified]';
  561.  
  562.   statusline := statusline+'  line: '+itoa(currline)+' of '+itoa(numlines);
  563.  
  564. {handle short-integer math}
  565.  
  566.   if numlines>600 then
  567.     perthrough := (10*currline) div (numlines div 10)
  568.   else if numlines>300 then
  569.     perthrough := (20*currline) div (numlines div 5)
  570.   else
  571.     perthrough := (100*currline) div numlines;
  572.  
  573.   if perthrough>100 then
  574.     perthrough := 100;   {handle roundoffs more gracefully!}
  575.  
  576.   statusline := statusline+' -- <'+itoa(perthrough)+'>% --';
  577.  
  578.   if length(statusline)<cols-15 then
  579.     statusline := statusline+'  Memory: <'+ltoa(maxavail div 1024)+'k>';
  580.  
  581.   setstatusline(statusline);
  582. end;
  583.  
  584.  
  585. { --- cursor positioning --- }
  586.  
  587.  
  588. procedure setcurrkeepcol(column: integer);
  589.  
  590. begin
  591.   currcol := column;
  592.   keeptocol := column;
  593. end;
  594.  
  595.  
  596. { --- file routines --- }
  597.  
  598.  
  599. procedure readfileinit;
  600.  
  601. begin
  602.   afterhead.next := nil;
  603.   tail := nil;
  604. end;
  605.  
  606. procedure readfilefixups;
  607.  
  608. begin
  609.   topline := 1;
  610.   currline := 1;
  611.   currptr := afterhead.next;
  612.   setcurrkeepcol(1);
  613.   counter := 0;
  614. end;
  615.  
  616. procedure returnmemorytopool;
  617.  
  618. begin
  619. {return all this memory to the unused pile}
  620.   tail^.next := unused;
  621.   unused := afterhead.next;
  622.  
  623.   readfileinit;
  624. end;
  625.  
  626. procedure readfile;
  627.  
  628. var
  629.   done: boolean;
  630.   newptr: ptr;
  631.   toolongline: boolean;
  632.   rotatepos: integer;
  633.  
  634. begin
  635.   numlines := 0;
  636.   toolongline := false;
  637.  
  638.   done := false;
  639.  
  640.   assign(thefile,filename);
  641.   {$I-}
  642.   reset(thefile);
  643.   {$I+}
  644.  
  645.   if ioresult<>0 then
  646.     begin
  647.       xwriteln;
  648.       xwritelns('warning: unable to open file -- starting');
  649.       xwrites('         with empty buffer: press any key ');
  650.       wastekey;
  651.     end
  652.   else
  653.     begin
  654.       rotatepos := 1;
  655.       while not eof(thefile) and not done do
  656.         begin
  657.           if numlines mod 16=0 then
  658.             begin
  659.               rotatepos := (rotatepos mod length(rotates))+1;
  660.               xwritess(copy(rotates,rotatepos,1),chr(8));
  661.             end;
  662.  
  663.           newptr := ptrafter(tail);
  664.           if newptr=nil then
  665.             done := true
  666.           else
  667.             begin
  668.               inc(numlines);
  669.               read(thefile,newptr^.str);
  670.  
  671.               if eoln(thefile) then
  672.                 readln(thefile)
  673.               else
  674.                 toolongline := true;
  675.  
  676. {$ifdef debug}
  677.               if debug then
  678.                 begin
  679.                   writeln('read in: ',newptr^.str);
  680.                   if newptr^.next<>nil then
  681.                     debugdie('nil error: '+newptr^.next^.str);
  682.                   if prev(newptr)^.next<>newptr then
  683.                     debugdie('prev/next error');
  684.                 end;
  685. {$endif}
  686.  
  687.             end;
  688.         end;
  689.  
  690.       if not eof(thefile) then
  691.         begin
  692.  
  693.       xwriteln;
  694.       xwritelns('warning: unable to read in complete file - operations');
  695.       xwrites('         which would add lines will not work: press any key ');
  696.  
  697.           wastekey;
  698.           changed := true;
  699.         end;
  700.  
  701.       if toolongline then
  702.         begin
  703.  
  704.       xwriteln;
  705.       xwrites('warning: some lines have been split:  press any key');
  706.  
  707.           wastekey;
  708.           changed := true;
  709.         end;
  710.  
  711.       close(thefile);
  712.     end;
  713.  
  714. {0-length file -- can't handle it -- there's always at least one line}
  715.  
  716.   if afterhead.next=nil then
  717.     begin
  718.       newptr := ptrafter(tail);
  719.       if newptr=nil then
  720.         begin
  721.           xwriteln;
  722.           xwritelns('actually, there seems to be no memory at all');
  723.           xwrites('   -- quitting now -- press any key ');
  724.           wastekey;
  725.           restorecolors;
  726.           halt(1);
  727.         end
  728.       else
  729.         begin
  730.           newptr^.str := '';
  731.           numlines := 1;
  732.         end;
  733.     end;
  734.  
  735.   changed := false;
  736.  
  737.   readfilefixups;
  738.  
  739.   refreshall;
  740.  
  741.   displayfileinfo;
  742. end;
  743.  
  744. procedure writefile(fn: string);
  745.  
  746. var
  747.   aptr: ptr;
  748.   written: boolean;
  749.  
  750. begin
  751.   setstatusline('writing...');
  752.  
  753.   written := true;
  754.  
  755. {should write to a temporary filename first!}
  756.  
  757.   assign(thefile,fn);
  758.   {$I+}
  759.   rewrite(thefile);
  760.   {$I-}
  761.   if ioresult<>0 then
  762.     begin
  763.       xwritelnsss(editorname,': could not write file ',fn);
  764.       written := false;
  765.     end
  766.   else
  767.     begin
  768.       aptr := afterhead.next;
  769.       while aptr<>nil do
  770.         begin
  771.  
  772. {took out trimming of lines - broke signature delimeter!}
  773. {no longer needed now that we don't have the stupid array anymore!}
  774.  
  775. {$I-}
  776.           writeln(thefile,aptr^.str);
  777. {$I+}
  778.           aptr := aptr^.next;
  779.  
  780.           if ioresult<>0 then
  781.             begin
  782.               warn('could not write file!  (out of space?)');
  783.               written := false;
  784.               aptr := nil;
  785.             end;
  786.         end;
  787.  
  788.       close(thefile);
  789.  
  790.       if written then
  791.         changed := false;
  792.     end;
  793.  
  794.   displayfileinfo;
  795. end;
  796.  
  797. procedure maybewritefile(fn: string);
  798.  
  799. begin
  800.   if changed then
  801.     writefile(fn);
  802. end;
  803.  
  804. procedure rereadfile;
  805.  
  806. begin
  807.   setstatusline('');
  808.  
  809.   returnmemorytopool;
  810.  
  811.   readfile;
  812.  
  813.   readfilefixups;
  814.  
  815.   refreshall;
  816.  
  817.   displayfileinfo;
  818. end;
  819.  
  820. procedure mayberereadfile;
  821.  
  822. var
  823.   y: char;
  824.   c: char;
  825.  
  826. begin
  827.   setstatusline('');
  828.   xwritexy(1,lpp,'reread file: ');
  829.  
  830.   if changed then
  831.     begin
  832.       xwrites('FILE HAS CHANGED!  ');
  833.       y := 'Y';
  834.     end
  835.   else
  836.     begin
  837.       xwrites('(file appears to not have changed) ');
  838.       y := 'y';
  839.     end;
  840.   xwrites('reread anyway?  '+y+'=yes, n=no ');
  841.  
  842.   repeat
  843.     c := xreadkey;
  844.   until (c=y) or (c='n');
  845.  
  846.   if c='n' then
  847.     setstatusline('')
  848.   else
  849.     rereadfile;
  850. end;
  851.  
  852. procedure insertasciifile(fn: string);
  853.  
  854. var
  855.   done: boolean;
  856.   insertionptr: ptr;
  857.   newptr: ptr;
  858.   toolongline: boolean;
  859.   rotatepos: integer;
  860.  
  861. begin
  862.   done := false;
  863.  
  864.   toolongline := false;
  865.  
  866.   assign(thefile,fn);
  867. {$I-}
  868.   reset(thefile);
  869. {$I+}
  870.   if ioresult<>0 then
  871.     setstatusline('could not read '+fn)
  872.   else
  873.     begin
  874.       changed := true;
  875.  
  876.       insertionptr := currptr;
  877.       newptr := currptr;
  878.       done := false;
  879.  
  880.       while not eof(thefile) and not done do
  881.         begin
  882.           rotatepos := 1;
  883.  
  884.           if numlines mod 16=0 then
  885.             begin
  886.               rotatepos := (rotatepos mod length(rotates))+1;
  887.               xwritess(copy(rotates,rotatepos,1),chr(8));
  888.             end;
  889.  
  890.           newptr := ptrafter(insertionptr);
  891.           if newptr=nil then
  892.             done := true
  893.           else
  894.             begin
  895.               inc(numlines);
  896.               read(thefile,newptr^.str);
  897.               insertionptr := newptr;
  898.  
  899.               if eoln(thefile) then
  900.                 readln(thefile)
  901.               else
  902.                 toolongline := true;
  903.  
  904. {$ifdef debug}
  905.               if debug then
  906.                 begin
  907.                   writeln('read in: ',newptr^.str);
  908.                   if newptr^.next<>nil then
  909.                     debugdie('nil error: '+newptr^.next^.str);
  910.                   if prev(newptr)^.next<>newptr then
  911.                     debugdie('prev/next error');
  912.                 end;
  913. {$endif}
  914.  
  915.             end;
  916.         end;
  917.  
  918.       if not eof(thefile) then
  919.         begin
  920.  
  921.       xwriteln;
  922.       xwritelns('warning: unable to read in complete file - operations');
  923.       xwrites('         which would add lines will not work: press any key ');
  924.  
  925.           wastekey;
  926.         end;
  927.  
  928.       close(thefile);
  929.  
  930.       refreshall;
  931.       displayfileinfo;
  932.     end;
  933. end;
  934.  
  935. procedure insertbinaryfile(fn: string);
  936.  
  937. const
  938.   buffersize=384;
  939.  
  940. var
  941.   failed: boolean;
  942.   insertionptr: ptr;
  943.   newptr: ptr;
  944.   rotatepos: integer;
  945.   binaryfile: file;
  946.   buf: array[1..buffersize] of byte;
  947.   numread: word;
  948.   uupos: integer;
  949.   uuline: string;
  950.   uulen: integer;
  951.  
  952.   procedure addline(astring: string);
  953.  
  954.   begin
  955.     if numlines mod 16=0 then
  956.       begin
  957.         rotatepos := (rotatepos mod length(rotates))+1;
  958.         xwritess(copy(rotates,rotatepos,1),chr(8));
  959.       end;
  960.  
  961.     newptr := ptrafter(insertionptr);
  962.     if newptr=nil then
  963.       failed := true
  964.     else
  965.       begin
  966.         inc(numlines);
  967.         newptr^.str := astring;
  968.         insertionptr := newptr;
  969.       end;
  970.   end;
  971.  
  972.   function uuchar(b: byte): char;
  973.  
  974.   begin
  975.     if b=0 then
  976.       uuchar := '`'
  977.     else
  978.       uuchar := chr(b+32);
  979.   end;
  980.  
  981.   procedure uue(l: integer; s: string);
  982.  
  983.   begin
  984.     addline(uuchar(l)+s);
  985.   end;
  986.  
  987.   procedure adduuch(n: integer; var l: integer; var s: string; b1,b2,b3: byte);
  988.  
  989.   begin
  990.     if length(s)>=60 then
  991.       begin
  992.         uue(l,s);
  993.         l := 0;
  994.         s := '';
  995.       end;
  996.  
  997.     s := s+uuchar(  (b1 and $fc) shr 2  );
  998.  
  999.     s := s+uuchar( ((b1 and $03) shl 4) or ((b2 and $f0) shr 4) );
  1000.  
  1001.     if n>1 then
  1002.       s := s+uuchar( ((b2 and $0f) shl 2) or ((b3 and $c0) shr 6) );
  1003.  
  1004.     if n>2 then
  1005.       s := s+uuchar(  (b3 and $3f)        );
  1006.  
  1007.     inc(l,n);
  1008.   end;
  1009.  
  1010. begin {insertbinaryfile}
  1011.   failed := false;
  1012.  
  1013.   rotatepos := 1;
  1014.  
  1015.   assign(binaryfile,fn);
  1016. {$I-}
  1017.   reset(binaryfile,1);
  1018. {$I+}
  1019.   if ioresult<>0 then
  1020.     setstatusline('could not read '+fn)
  1021.   else
  1022.     begin
  1023.       changed := true;
  1024.  
  1025.       insertionptr := currptr;
  1026.       newptr := currptr;
  1027.  
  1028.       addline('');
  1029.       if not failed then
  1030.         addline('begin 600 '+fn);
  1031.  
  1032.       uuline := '';
  1033.       uulen := 0;
  1034.  
  1035.       repeat
  1036.         blockread(binaryfile,buf,buffersize,numread);
  1037.         uupos := 1;
  1038.         while uupos<=numread do
  1039.           begin
  1040.             if uupos=numread then
  1041.               adduuch(1,uulen,uuline,buf[uupos],0,0)
  1042.             else if uupos=numread-1 then
  1043.               adduuch(2,uulen,uuline,buf[uupos],buf[uupos+1],0)
  1044.             else
  1045.               adduuch(3,uulen,uuline,buf[uupos],buf[uupos+1],buf[uupos+2]);
  1046.             inc(uupos,3);
  1047.           end;
  1048.       until (numread<buffersize) or failed;
  1049.  
  1050.       if (uuline<>'') and not failed then
  1051.         uue(uulen,uuline);
  1052.  
  1053.       if not failed then
  1054.         uue(0,'');
  1055.  
  1056.       if not failed then
  1057.         addline('end');
  1058.  
  1059.       if not failed then
  1060.         addline('');
  1061.  
  1062.       if failed then
  1063.         begin
  1064.  
  1065.       xwriteln;
  1066.       xwritelns('warning: unable to read in complete file - operations');
  1067.       xwrites('         which would add lines will not work: press any key ');
  1068.  
  1069.           wastekey;
  1070.         end;
  1071.  
  1072.       close(binaryfile);
  1073.  
  1074.       refreshall;
  1075.       displayfileinfo;
  1076.     end;
  1077. end;
  1078.  
  1079. procedure insertfile(fn: string);
  1080.  
  1081. begin
  1082.   if not fexists(fn) then
  1083.     setstatusline('<'+fn+'> does not exist')
  1084.   else
  1085.     begin
  1086.       if isasciifile(fn) then
  1087.         insertasciifile(fn)
  1088.       else
  1089.         insertbinaryfile(fn);
  1090.     end;
  1091. end;
  1092.  
  1093. procedure writetofile(fn: string);
  1094.  
  1095. begin
  1096.   writefile(fn);
  1097. end;
  1098.  
  1099. procedure maybewritetofile(fn: string);
  1100.  
  1101. begin
  1102.   if not fexists(fn) then
  1103.     writetofile(fn)
  1104.   else
  1105.     setstatusline('<'+fn+'> exists -- use :w! to force');
  1106. end;
  1107.  
  1108. procedure newfile(fn: string);
  1109.  
  1110. begin
  1111.   returnmemorytopool;
  1112.  
  1113.   alternatefilename := filename;
  1114.   filename := fn;
  1115.  
  1116.   readfile;
  1117.  
  1118.   readfilefixups;
  1119.  
  1120.   refreshall;
  1121.  
  1122.   displayfileinfo;
  1123. end;
  1124.  
  1125. procedure maybenewfile(fn: string);
  1126.  
  1127. begin
  1128.   if not changed then
  1129.     newfile(fn)
  1130.   else
  1131.     setstatusline('file has changed -- use :e! to force');
  1132. end;
  1133.  
  1134.  
  1135. { --- counter stuff --- }
  1136.  
  1137.  
  1138. procedure addtocounter(i: integer);
  1139.  
  1140. begin
  1141.  
  1142. {cutoff is really 3276 or so}
  1143.  
  1144.   if counter<3000 then
  1145.     counter := counter*10+i;
  1146. end;
  1147.  
  1148. function usecounterdefault(defaultvalue: integer): integer;
  1149.  
  1150. var
  1151.   result: integer;
  1152.  
  1153. begin
  1154.   result := counter;
  1155.   if result=0 then
  1156.     result := defaultvalue;
  1157.  
  1158.   counter := 0;
  1159.  
  1160.   usecounterdefault := result;
  1161. end;
  1162.  
  1163. function usecounter: integer;
  1164.  
  1165. begin
  1166.   usecounter := usecounterdefault(1);
  1167. end;
  1168.  
  1169.  
  1170. { --- editing stuff --- }
  1171.  
  1172.  
  1173. function isnewlineafter(aptr: ptr): boolean;
  1174.  
  1175. var
  1176.   result: boolean;
  1177.   wasteptr: ptr;
  1178.  
  1179. begin
  1180.   wasteptr := ptrafter(aptr);
  1181.   result := (wasteptr<>nil);
  1182.  
  1183.   if result then
  1184.     inc(numlines)
  1185.   else
  1186.     warn('not enough memory to add another line');
  1187.  
  1188.   isnewlineafter := result;
  1189. end;
  1190.  
  1191. procedure deletelineafter(aptr: ptr);
  1192.  
  1193. begin
  1194.   if numlines<2 then
  1195.     begin
  1196.       currptr^.str := '';
  1197.       numlines := 1;
  1198.     end
  1199.   else
  1200.     begin
  1201.       deleteptr(aptr^.next);
  1202.       dec(numlines);
  1203.     end;
  1204. end;
  1205.  
  1206. procedure delcharat(var s: string; col: integer);
  1207.  
  1208. begin
  1209.   if col<=length(s) then
  1210.     begin
  1211.       if col=1 then
  1212.         s := copy(s,2,255)
  1213.       else if col=length(s) then
  1214.         s := copy(s,1,col-1)
  1215.       else
  1216.         s := copy(s,1,col-1)+copy(s,col+1,255);
  1217.     end;
  1218. end;
  1219.  
  1220. function botline: integer;
  1221.  
  1222. begin
  1223.   botline := topline+editinglpp-1;
  1224. end;
  1225.  
  1226. function offscreen(lineno: integer): boolean;
  1227.  
  1228. begin
  1229.   offscreen := (lineno>botline) or (lineno<topline);
  1230. end;
  1231.  
  1232. procedure refreshaptr(aptr: ptr; lineat: integer);
  1233.  
  1234. begin
  1235.  
  1236. {$ifdef debug}
  1237.   if debug then
  1238.     if aptr=nil then
  1239.       debugdie('refreshaptr(nil)!');
  1240. {$endif}
  1241.  
  1242.   xclreolxy(1,lineat);
  1243.  
  1244. {it can edit long lines -- kind of -- as long as they're not displayed}
  1245.  
  1246.   if aptr<>nil then
  1247.     xwrites(copy(aptr^.str,1,cols-1));
  1248.  
  1249. {$ifdef debug}
  1250.   if debug then
  1251.     if cols>20 then
  1252.       begin
  1253.         xgotoxy(cols-10,lineat);
  1254.         xwrites(': ');
  1255.         xwritei(aptr^.seq);
  1256.         xwrites(' :');
  1257.       end;
  1258. {$endif}
  1259.  
  1260. end;
  1261.  
  1262. procedure refreshaline(lineat: integer);
  1263.  
  1264. var
  1265.   refreshptr: ptr;
  1266.  
  1267. begin
  1268.   refreshptr := nthptr(topline+lineat-1);
  1269.  
  1270. {$ifdef debug}
  1271.   if debug then
  1272.     if refreshptr=nil then
  1273.       begin
  1274.         writeln;
  1275.         writeln('nthptr(',topline+lineat-1,')=nil!');
  1276.         debugdie('');
  1277.       end;
  1278. {$endif}
  1279.  
  1280.   if refreshptr<>nil then
  1281.     refreshaptr(refreshptr,lineat);
  1282. end;
  1283.  
  1284. procedure refreshline;
  1285.  
  1286. begin
  1287.   refreshaline(currline-topline+1);
  1288.   reposcurs;
  1289. end;
  1290.  
  1291. procedure refreshpart(top, bottom: integer);
  1292.  
  1293. var
  1294.   i: integer;
  1295.   refreshptr: ptr;
  1296.  
  1297. begin
  1298.   refreshptr := nthptr(topline+top-1);
  1299.  
  1300. {$ifdef debug}
  1301.   if debug then
  1302.     if refreshptr=nil then
  1303.       begin
  1304.         writeln;
  1305.         writeln('nthptr(topline+top-1=',topline,'+',top,'-1)=nil!');
  1306.         debugdie('');
  1307.       end;
  1308. {$endif}
  1309.  
  1310.   for i := top to bottom do
  1311.     if refreshptr<>nil then
  1312.       begin
  1313.         refreshaptr(refreshptr,i);
  1314.         refreshptr := refreshptr^.next;
  1315.       end;
  1316.  
  1317.   restorecurs;
  1318. end;
  1319.  
  1320. procedure showhelp;
  1321.  
  1322. begin
  1323.   xgotoxy(1,lpp-3);
  1324.   xwritehighlights(
  1325.    '<q>uit <w>rite to disk <j>=down <k>=up <h>=left <l>=right '+
  1326.    '<^F>=forward page <^B>=back page');
  1327.  
  1328.   xgotoxy(1,lpp-2);
  1329.   xwritehighlights(
  1330.    '<z>=bighelp <x>=del <i>nsert/<a>ppend (<Esc> when done) <^L>=refresh '+
  1331.    '<1G>=top <G>=bottom');
  1332.  
  1333. end;
  1334.  
  1335. procedure refreshall;
  1336.  
  1337. begin
  1338.   xclrscr;
  1339.   if alwayshelp then
  1340.     showhelp;
  1341.  
  1342.   refreshpart(1,editinglpp);
  1343. end;
  1344.  
  1345. procedure refreshcurrlineandbelow;
  1346.  
  1347. begin
  1348.   refreshpart(currline-topline+1,editinglpp);
  1349. end;
  1350.  
  1351. procedure currnextline;
  1352.  
  1353. begin
  1354.   if currptr^.next<>nil then
  1355.     begin
  1356.       currptr := currptr^.next;
  1357.       inc(currline);
  1358.     end;
  1359. end;
  1360.  
  1361. procedure currprevline;
  1362.  
  1363. var
  1364.   prevptr: ptr;
  1365.  
  1366. begin
  1367.   prevptr := prev(currptr);
  1368.   currptr := prevptr;
  1369.   dec(currline);
  1370. end;
  1371.  
  1372. procedure bighelp;
  1373.  
  1374. begin
  1375.   xclrscr;
  1376.   xgotoxy(1,1);
  1377.   xwritess('trivial editor: ',editorname);
  1378.   xwritess(' version ',editorversion);
  1379.   xwrites('   small memory, local+remote use');
  1380.  
  1381.   xgotoxy(1,2);
  1382.   xwrites('Russell Schulz   russell@alpha3.ersys.edmonton.ab.ca (950423)');
  1383.  
  1384. {
  1385.   xgotoxy(1,4);
  1386.   xwritehighlights(
  1387.    'vi cursor keys: <h>=left, <l>=right  <^F>=forward page  <1G> first line');
  1388.   xgotoxy(1,5);
  1389.   xwritehighlights(
  1390.    '                <j>=down, <k>=up     <^B>=back page     <G> last line');
  1391. }
  1392.  
  1393.   xgotoxy(1,4);
  1394.   xwritehighlights(
  1395.    'vi cursor keys:        <k>=up      <^F>=forward page  <1G> first line');
  1396.   xgotoxy(1,5);
  1397.   xwritehighlights(
  1398.    '                left=<h>  <l>=right  <^B>=back page     <G> last line');
  1399.   xgotoxy(1,6);
  1400.   xwritehighlights(
  1401.    '                      <j>=down');
  1402.  
  1403.   xgotoxy(1,8);
  1404.   xwritehighlights(
  1405.    '<x>=delete current character   <X>=delete left');
  1406.   xgotoxy(1,9);
  1407.   xwritehighlights(
  1408.    '<i>nsert characters at, <a>ppend characters after cursor');
  1409.   xgotoxy(1,10);
  1410.   xwritehighlights(
  1411.    '  <Esc> to exit');
  1412.  
  1413.   xgotoxy(1,12);
  1414.   xwritehighlights(
  1415.    '<s>plit line after cursor   <J>oin line with next');
  1416.   xgotoxy(1,13);
  1417.   xwritehighlights(
  1418.    '<o>pen a new line below current one (and insert)');
  1419.   xgotoxy(1,14);
  1420.   xwritehighlights(
  1421.    '<O>=open a new line above current one (and insert)');
  1422.   xgotoxy(1,15);
  1423.   xwritehighlights(
  1424.    '<D>elete current line  <Y>ank current line  <p>aste after');
  1425.   xgotoxy(1,16);
  1426.   xwritehighlights(
  1427.    '<^>=start of line  <$>=end                  <P>=paste before');
  1428.   xgotoxy(1,17);
  1429.   xwritehighlights(
  1430.    '<H>igh <M>id <L>ow line on screen     <~>=change capitalization');
  1431.  
  1432.   xgotoxy(1,19);
  1433.   xwritehighlights(
  1434.    '<^R>=reread file from disk (discarding all changes)');
  1435.   xgotoxy(1,20);
  1436.   xwritehighlights(
  1437.    '<^L>=refresh screen     <^G>=show file info');
  1438.  
  1439.   xgotoxy(1,23);
  1440.   xwritehighlights(
  1441.    '<w>rite and continue editing   <q>uit');
  1442.  
  1443. {$ifdef oldhelp}
  1444.   xwritexy(1,6 ,'vi cursor keys: h=left, l=right    ^f=forward page');
  1445.   xwritexy(1,7 ,'                j=down, k=up       ^b=back page');
  1446.  
  1447.   xwritexy(1,9 ,'x=delete current character   X=delete left');
  1448.   xwritexy(1,10,'i=insert characters at, a=append characters after cursor');
  1449.   xwritexy(1,11,'  Enter or Esc to exit  (restricted to one line right now)');
  1450.  
  1451.   xwritexy(1,13,'s=split line after cursor   J=join line with next');
  1452.   xwritexy(1,14,'o=open a new line below current one (and insert)');
  1453.   xwritexy(1,15,'O=open a new line above current one (and insert)');
  1454.   xwritexy(1,16,'D=delete current line  Y=yank current line  p=paste after');
  1455.   xwritexy(1,17,'^=start of line  $=end                      P=paste before');
  1456.   xwritexy(1,18,'1G=top of file G=bottom  H=high line on screen M=mid L=low');
  1457.  
  1458.   xwritexy(1,20,'^R=reread file from disk (discarding all changes)');
  1459.   xwritexy(1,21,'^L=refresh screen     ^G=show file info');
  1460.  
  1461.   xwritexy(1,23,'w=write and continue editing   q=quit');
  1462. {$endif}
  1463.  
  1464.   xwritexy(1,lpp,'press any key ');
  1465.   wastekey;
  1466.  
  1467.   refreshall;
  1468. end;
  1469.  
  1470. procedure help;
  1471.  
  1472. begin
  1473.   if alwayshelp then
  1474.     bighelp
  1475.   else
  1476.     setstatusline(
  1477.      '<z>=bighelp,<q>uit,<j>=down,<k>=up,<h>=left,<l>=right,'+
  1478.      '<x>=del,<i>ns,<^L>=refresh');
  1479. end;
  1480.  
  1481. procedure undo;
  1482.  
  1483. var
  1484.   undosavestring: string;
  1485.  
  1486. begin
  1487.   if undoline<>0 then
  1488.     begin
  1489.       if undoline<=numlines then
  1490.         begin
  1491.           setcurrlineptr(undoline);
  1492.  
  1493. {save it, to allow for hitting `u' twice in a row to redo}
  1494.           undosavestring := currptr^.str;
  1495.           currptr^.str := undostring;
  1496.           undostring := undosavestring;
  1497.  
  1498.           if offscreen(currline) then
  1499.             begin
  1500.               topline := max(1,undoline-2);
  1501.               refreshall;
  1502.             end
  1503.           else
  1504.             refreshline;
  1505.         end
  1506.       else
  1507.         begin
  1508.           warn('cannot undo this yet, sorry');
  1509.         end
  1510.     end;
  1511. end;
  1512.  
  1513. procedure downaline;
  1514.  
  1515. var
  1516.   needrefresh: boolean;
  1517.   countup: integer;
  1518.  
  1519. begin
  1520.   needrefresh := false;
  1521.  
  1522.   for countup := 1 to usecounter do
  1523.     begin
  1524.       if currptr^.next<>nil then
  1525.         begin
  1526.           currnextline;
  1527.           if offscreen(currline) then
  1528.             begin
  1529.               topline := min(topline+4,numlines);
  1530.               needrefresh := true;
  1531.             end;
  1532.         end;
  1533.     end;
  1534.  
  1535.   if needrefresh then
  1536.     refreshall;
  1537.  
  1538.   restorecurs;
  1539. end;
  1540.  
  1541. procedure upaline;
  1542.  
  1543. var
  1544.   needrefresh: boolean;
  1545.   countup: integer;
  1546.  
  1547. begin
  1548.   needrefresh := false;
  1549.  
  1550.   for countup := 1 to usecounter do
  1551.     begin
  1552.       if currptr<>afterhead.next then
  1553.         begin
  1554.           currprevline;
  1555.           if offscreen(currline) then
  1556.             begin
  1557.               topline := max(topline-4,1);
  1558.               needrefresh := true;
  1559.             end;
  1560.         end;
  1561.     end;
  1562.  
  1563.   if needrefresh then
  1564.     refreshall;
  1565.   restorecurs;
  1566. end;
  1567.  
  1568. procedure rightachar;
  1569.  
  1570. var
  1571.   countup: integer;
  1572.  
  1573. begin
  1574.   for countup := 1 to usecounter do
  1575.     if currcol<currlength then
  1576.       setcurrkeepcol(currcol+1);
  1577.  
  1578.   restorecurs;
  1579. end;
  1580.  
  1581. procedure leftachar;
  1582.  
  1583. var
  1584.   countup: integer;
  1585.  
  1586. begin
  1587.   for countup := 1 to usecounter do
  1588.     if currcol>1 then
  1589.       setcurrkeepcol(currcol-1);
  1590.  
  1591.   restorecurs;
  1592. end;
  1593.  
  1594. procedure delchar;
  1595.  
  1596. var
  1597.   needrefresh: boolean;
  1598.   countup: integer;
  1599.  
  1600. begin
  1601.   itmightchange;
  1602.  
  1603.   needrefresh := false;
  1604.  
  1605.   for countup := 1 to usecounter do
  1606.     if currcol<=currlength then
  1607.       begin
  1608.         ithaschanged;
  1609.         delcharat(currptr^.str,currcol);
  1610.  
  1611. {trivial screen optimization}
  1612.  
  1613.         if (currcol>currlength) and not needrefresh then
  1614.           begin
  1615.             xwrites(' ');
  1616.             restorecurs;
  1617.           end
  1618.         else
  1619.           needrefresh := true;
  1620.  
  1621.         if currcol>currlength then
  1622.           setcurrkeepcol(currlength);
  1623.       end;
  1624.  
  1625.   restorecurs;
  1626.  
  1627.   if needrefresh then
  1628.     refreshline;
  1629. end;
  1630.  
  1631. procedure delcharleft;
  1632.  
  1633. var
  1634.   needrefresh: boolean;
  1635.   countup: integer;
  1636.  
  1637. begin
  1638.   itmightchange;
  1639.  
  1640.   needrefresh := false;
  1641.  
  1642.   for countup := 1 to usecounter do
  1643.     if currcol>1 then
  1644.       begin
  1645.         ithaschanged;
  1646.  
  1647.         setcurrkeepcol(currcol-1);
  1648.         delcharat(currptr^.str,currcol);
  1649.  
  1650.         needrefresh := true;
  1651.       end;
  1652.  
  1653.   restorecurs;
  1654.  
  1655.   if needrefresh then
  1656.     refreshline;
  1657. end;
  1658.  
  1659. procedure insert;
  1660.  
  1661. var
  1662.   c: char;
  1663.   doneline: boolean;
  1664.   doneins: boolean;
  1665.   newptr: ptr;
  1666.   blanklinesinarow: integer;  {user tolerance}
  1667.  
  1668. begin
  1669.   itmightchange;
  1670.  
  1671.   if alwayshelp then
  1672.     setstatusline('use <Esc> to exit');
  1673.  
  1674.   blanklinesinarow := 0;
  1675.  
  1676.   doneins := false;
  1677.   while not doneins do
  1678.     begin
  1679.       doneline := false;
  1680.       while not doneline and not doneins do
  1681.         begin
  1682.           c := xreadkey;
  1683.  
  1684.           {delete backwards}
  1685.           if (c=#8) or (c=#127) then
  1686.             begin
  1687.               if (currcol>1) and (currcol<=currlength+1) then
  1688.                 begin
  1689.                   ithaschanged;
  1690.  
  1691. {trivial screen optimization if this is last char on line - common case}
  1692.  
  1693.                   if currcol>currlength then
  1694.                     begin
  1695.                       setcurrkeepcol(currcol-1);
  1696.                       delcharat(currptr^.str,currcol);
  1697.                       reposcurs;
  1698.                       xwrites(' ');
  1699.                       reposcurs;
  1700.                     end
  1701.                   else
  1702.                     begin
  1703.                       setcurrkeepcol(currcol-1);
  1704.                       delcharat(currptr^.str,currcol);
  1705.                       refreshline;
  1706.                     end;
  1707.                 end;
  1708.             end
  1709.           else if (c=#13) then
  1710.             begin
  1711.               doneline := true;
  1712.             end
  1713.           else if (c=#27) then
  1714.             begin
  1715.               doneins := true;
  1716.             end
  1717.           else if (ord(c)>=32) and (eightbitclean or (ord(c)<127)) then
  1718.             begin
  1719.               ithaschanged;
  1720.  
  1721. {trivial screen optimization if this is last character - very common case}
  1722.  
  1723.               if currcol>currlength then
  1724.                 begin
  1725.                   currptr^.str := currptr^.str+c;
  1726.                   reposcurs;
  1727.                   xwrites(c);
  1728.                   setcurrkeepcol(currcol+1);
  1729.                 end
  1730.               else
  1731.                 begin
  1732.                   if currcol=1 then
  1733.                     currptr^.str := c+currptr^.str
  1734.                   else
  1735.                     currptr^.str :=
  1736.                      copy(currptr^.str,1,currcol-1)+c+
  1737.                      copy(currptr^.str,currcol,255);
  1738.                   setcurrkeepcol(currcol+1);
  1739.                   refreshline;
  1740.                 end;
  1741.             end;
  1742.  
  1743.           if currlength>=250 then
  1744.             doneline := true;
  1745.  
  1746.         end;     {doneline}
  1747.  
  1748.     if not doneins then
  1749.       begin
  1750.         if currptr^.str='' then
  1751.           inc(blanklinesinarow)
  1752.         else
  1753.           blanklinesinarow := 0;
  1754.  
  1755.         newptr := ptrafter(currptr);
  1756.         if newptr=nil then
  1757.           begin
  1758.             doneins := true;
  1759.             warn('out of memory');
  1760.           end
  1761.         else
  1762.           begin
  1763.             inc(numlines);
  1764.  
  1765.             setcurrkeepcol(1);
  1766.             setcurrlineptr(currline+1);
  1767.  
  1768.             if offscreen(currline) then
  1769.               begin
  1770.                 topline := min(topline+4,numlines);
  1771.                 refreshall;
  1772.               end
  1773.             else
  1774.               refreshcurrlineandbelow;
  1775.  
  1776.             if alwayshelp then
  1777.               setstatusline('use <Esc> to exit')
  1778.             else if blanklinesinarow>3 then
  1779.               begin
  1780.                 setstatusline('use <Esc> to exit');
  1781.                 blanklinesinarow := 0;
  1782.               end;
  1783.           end
  1784.       end;
  1785.  
  1786.   end;    {doneins}
  1787.  
  1788.   setstatusline('');
  1789.  
  1790. {vi would do a cursorleft here}
  1791.   restorecurs;
  1792. end;
  1793.  
  1794. procedure append;
  1795.  
  1796. begin
  1797.   inc(currcol);
  1798.   reposcurs;
  1799.   insert;
  1800. end;
  1801.  
  1802. procedure replace;
  1803.  
  1804. var
  1805.   c: char;
  1806.  
  1807. begin
  1808.   itmightchange;
  1809.  
  1810.   if currcol<=currlength then
  1811.     begin
  1812.       c := xreadkey;
  1813.       if c<>#27 then
  1814.         begin
  1815.           ithaschanged;
  1816.           currptr^.str[currcol] := c;
  1817.           xwrites(c);
  1818.           restorecurs;
  1819.         end;
  1820.     end;
  1821. end;
  1822.  
  1823. procedure replacemuch;
  1824.  
  1825. var
  1826.   c: char;
  1827.   done: boolean;
  1828.  
  1829. begin
  1830.   itmightchange;
  1831.  
  1832.   done := false;
  1833.  
  1834.   while (currcol<=currlength) and not done do
  1835.     begin
  1836.       c := xreadkey;
  1837.       if c=#27 then
  1838.         done := true
  1839.       else
  1840.         begin
  1841.           ithaschanged;
  1842.           currptr^.str[currcol] := c;
  1843.           xwrites(c);
  1844.           setcurrkeepcol(currcol+1);
  1845.           keeptocol := currcol-1;
  1846.         end;
  1847.     end;
  1848. end;
  1849.  
  1850. procedure gotocol;
  1851.  
  1852. begin
  1853.   setcurrkeepcol(usecounter);
  1854.   restorecurs;
  1855. end;
  1856.  
  1857. procedure gofirstcol;
  1858.  
  1859. begin
  1860.   setcurrkeepcol(1);
  1861.   restorecurs;
  1862. end;
  1863.  
  1864. procedure gofirstnonblankcol;
  1865.  
  1866. var
  1867.   newcol: integer;
  1868.   i: integer;
  1869.  
  1870. begin
  1871.   if currlength<2 then
  1872.     newcol := 1
  1873.   else
  1874.     begin
  1875.       newcol := 0;
  1876.       for i := 1 to currlength do
  1877.         if newcol=0 then
  1878.           if (currptr^.str[i]<>' ') and (currptr^.str[i]<>tab) then
  1879.             newcol := i;
  1880.       if newcol=0 then
  1881.         newcol := 1;
  1882.     end;
  1883.  
  1884.   setcurrkeepcol(newcol);
  1885.   restorecurs;
  1886. end;
  1887.  
  1888. procedure golastcol;
  1889.  
  1890. begin
  1891.   setcurrkeepcol(currlength);
  1892.   keeptocol := maxint;
  1893.  
  1894.   restorecurs;
  1895. end;
  1896.  
  1897. procedure split;
  1898.  
  1899. var
  1900.   oldstr: string;
  1901.  
  1902. begin
  1903.   itmightchange;
  1904.  
  1905.   if isnewlineafter(currptr) then
  1906.     begin
  1907.       ithaschanged;
  1908.       oldstr := currptr^.str;
  1909.       currptr^.str := copy(oldstr,1,currcol-1);
  1910.       currptr^.next^.str := copy(oldstr,currcol,255);
  1911.  
  1912. {trivial screen optimization}
  1913.  
  1914.       refreshcurrlineandbelow;
  1915.  
  1916.       restorecurs;
  1917.     end;
  1918.  
  1919.   keeptocol := currcol;
  1920. end;
  1921.  
  1922. procedure combine;
  1923.  
  1924. begin
  1925.   itmightchange;
  1926.  
  1927.   if currptr^.next<>nil then
  1928.     if currlength+length(currptr^.next^.str)<254 then
  1929.       begin
  1930.         ithaschanged;
  1931.  
  1932.         golastcol;
  1933.  
  1934.         currptr^.str := currptr^.str+' '+currptr^.next^.str;
  1935.         deletelineafter(currptr);
  1936.  
  1937. {trivial screen optimization}
  1938.  
  1939.         refreshcurrlineandbelow;
  1940.       end;
  1941. end;
  1942.  
  1943. procedure openbelow;
  1944.  
  1945. begin
  1946.   itmightchange;
  1947.  
  1948.   keeptocol := 1;
  1949.  
  1950.   if isnewlineafter(currptr) then
  1951.     begin
  1952.       ithaschanged;
  1953.       currnextline;
  1954.  
  1955. {trivial screen optimization}
  1956.  
  1957.       if offscreen(currline) then
  1958.         begin
  1959.           inc(topline);
  1960.           refreshall;
  1961.         end
  1962.       else
  1963.         refreshcurrlineandbelow;
  1964.  
  1965.       insert;
  1966.     end;
  1967. end;
  1968.  
  1969. procedure openabove;
  1970.  
  1971. var
  1972.   aptr: ptr;
  1973.   prevptr: ptr;
  1974.  
  1975. begin
  1976.   itmightchange;
  1977.  
  1978.   prevptr := prev(currptr);
  1979.   if isnewlineafter(prevptr) then
  1980.     begin
  1981.       ithaschanged;
  1982.  
  1983.       setcurrlineptr(currline);
  1984.  
  1985.       refreshcurrlineandbelow;
  1986.       insert;
  1987.     end;
  1988.  
  1989.   keeptocol := 1;
  1990. end;
  1991.  
  1992. procedure pastebefore;
  1993.  
  1994. var
  1995.   aptr: ptr;
  1996.   prevptr: ptr;
  1997.  
  1998. begin
  1999.   itmightchange;
  2000.  
  2001.   prevptr := prev(currptr);
  2002.   if isnewlineafter(prevptr) then
  2003.     begin
  2004.       ithaschanged;
  2005.  
  2006.       setcurrlineptr(currline);
  2007.  
  2008.       currptr^.str := bufferedstring;
  2009.  
  2010. {trivial screen optimization}
  2011.  
  2012.       if offscreen(currline) then
  2013.         begin
  2014.           inc(topline);
  2015.           refreshall;
  2016.         end
  2017.       else
  2018.         refreshcurrlineandbelow;
  2019.  
  2020.     end;
  2021.  
  2022.   keeptocol := currcol;
  2023. end;
  2024.  
  2025. procedure pasteafter;
  2026.  
  2027. begin
  2028.   itmightchange;
  2029.  
  2030.   if isnewlineafter(currptr) then
  2031.     begin
  2032.       ithaschanged;
  2033.  
  2034.       currnextline;
  2035.       currptr^.str := bufferedstring;
  2036.  
  2037. {trivial screen optimization}
  2038.  
  2039.       if offscreen(currline) then
  2040.         begin
  2041.           inc(topline);
  2042.           refreshall;
  2043.         end
  2044.       else
  2045.         refreshcurrlineandbelow;
  2046.     end;
  2047.  
  2048.   keeptocol := currcol;
  2049. end;
  2050.  
  2051. procedure deleteline;
  2052.  
  2053. var
  2054.   prevptr: ptr;
  2055.   needrefresh: boolean;
  2056.   countup: integer;
  2057.  
  2058. begin
  2059.   itmightchange;
  2060.  
  2061.   needrefresh := false;
  2062.  
  2063.   for countup := 1 to usecounter do
  2064.     begin
  2065.       ithaschanged;
  2066.  
  2067.       bufferedstring := currptr^.str;
  2068.  
  2069. {don't leave that last line dangle if it's on the screen now -- it won't later}
  2070.  
  2071.       if not offscreen(numlines) then
  2072.         xclreolxy(1,numlines-topline+1);
  2073.  
  2074.       prevptr := prev(currptr);
  2075.  
  2076.       deletelineafter(prevptr);
  2077.       currptr := prevptr;
  2078.  
  2079. {currline can get out of sync here, but it's fixed up right away}
  2080.       if currptr^.next<>nil then
  2081.         currptr := currptr^.next;
  2082.  
  2083. {trivial screen optimization}
  2084.  
  2085.       if currline>numlines then
  2086.         begin
  2087.           dec(currline);
  2088.           if offscreen(currline) then
  2089.             begin
  2090.               dec(topline,3*(editinglpp div 4));
  2091.               if topline<1 then
  2092.                 topline := 1;
  2093.               needrefresh := true;
  2094.             end;
  2095.           restorecurs;
  2096.         end
  2097.       else
  2098.         refreshcurrlineandbelow;
  2099.  
  2100.     end;
  2101.  
  2102.   if needrefresh then
  2103.     refreshall;
  2104.  
  2105.   keeptocol := currcol;
  2106. end;
  2107.  
  2108. procedure yankline;
  2109.  
  2110. begin
  2111.   bufferedstring := currptr^.str;
  2112. end;
  2113.  
  2114. procedure gotoline;
  2115.  
  2116. var
  2117.   newcurrline: integer;
  2118.  
  2119. begin
  2120.   newcurrline := min(usecounterdefault(numlines),numlines);
  2121.  
  2122.   if newcurrline=numlines then
  2123.     begin
  2124.       currline := numlines;
  2125.       currptr := tail;
  2126.     end
  2127.   else
  2128.     setcurrlineptr(newcurrline);
  2129.  
  2130.   if offscreen(currline) then
  2131.     begin
  2132.       topline := max(currline-editinglpp+2,1);
  2133.       refreshall;
  2134.     end;
  2135.  
  2136.   restorecurs;
  2137. end;
  2138.  
  2139. procedure goforwardpg;
  2140.  
  2141. begin
  2142.   if offscreen(numlines) then
  2143.     begin
  2144.       setcurrlineptr(min(numlines,currline+editinglpp-2));
  2145.       topline := min(numlines,topline+editinglpp-2);
  2146.       refreshall;
  2147.     end
  2148.   else
  2149.     begin
  2150.       setcurrlineptr(numlines);
  2151.     end;
  2152.  
  2153.   restorecurs;
  2154. end;
  2155.  
  2156. procedure gobackpg;
  2157.  
  2158. begin
  2159.   if not offscreen(1) then
  2160.     setcurrlineptr(1)
  2161.   else
  2162.     begin
  2163.       setcurrlineptr(max(1,currline-(editinglpp-2)));
  2164.       topline := max(1,topline-(editinglpp-2));
  2165.       refreshall;
  2166.     end;
  2167.  
  2168.   restorecurs;
  2169. end;
  2170.  
  2171. procedure scrollup;
  2172.  
  2173. var
  2174.   needrefresh: boolean;
  2175.   countup: integer;
  2176.  
  2177. begin
  2178.   needrefresh := false;
  2179.  
  2180.   for countup := 1 to usecounter do
  2181.     if topline>1 then
  2182.       begin
  2183.         needrefresh := true;
  2184.         dec(topline);
  2185.         if offscreen(currline) then
  2186.           setcurrlineptr(currline-1);
  2187.     end;
  2188.  
  2189.   if needrefresh then
  2190.     refreshall;
  2191. end;
  2192.  
  2193. procedure scrolldown;
  2194.  
  2195. var
  2196.   needrefresh: boolean;
  2197.   countup: integer;
  2198.  
  2199. begin
  2200.   needrefresh := false;
  2201.  
  2202.   for countup := 1 to usecounter do
  2203.     if topline<numlines then
  2204.       begin
  2205.         needrefresh := true;
  2206.         inc(topline);
  2207.         if offscreen(currline) then
  2208.           setcurrlineptr(currline+1);
  2209.     end;
  2210.  
  2211.   if needrefresh then
  2212.     refreshall;
  2213. end;
  2214.  
  2215. procedure gohighline;
  2216.  
  2217. begin
  2218.   setcurrlineptr(topline);
  2219.   restorecurs;
  2220. end;
  2221.  
  2222. procedure golowline;
  2223.  
  2224. begin
  2225.   setcurrlineptr(min(botline,numlines));
  2226.   restorecurs;
  2227. end;
  2228.  
  2229. procedure gomidline;
  2230.  
  2231. begin
  2232.   setcurrlineptr((topline+min(botline,numlines)) div 2);
  2233.   restorecurs;
  2234. end;
  2235.  
  2236. procedure changecase;
  2237.  
  2238. var
  2239.   c: char;
  2240.  
  2241. begin
  2242.   itmightchange;
  2243.  
  2244.   if currcol<=currlength then
  2245.     begin
  2246.       c := currptr^.str[currcol];
  2247.       if isalpha(c) then
  2248.         begin
  2249.           ithaschanged;
  2250.           if islower(c) then
  2251.             c := upcase(c)
  2252.           else
  2253.             c := lowcase(c);
  2254.           currptr^.str[currcol] := c;
  2255.           xwrites(c);
  2256.         end;
  2257.  
  2258.       if currcol<currlength then
  2259.         setcurrkeepcol(currcol+1);
  2260.  
  2261.       restorecurs;
  2262.     end;
  2263. end;
  2264.  
  2265. procedure quit;
  2266.  
  2267. var
  2268.   c: char;
  2269.   keylist: string;
  2270.  
  2271. begin
  2272.   setstatusline('');
  2273.  
  2274.   if changed then
  2275.     begin
  2276.       xwritexy(1,lpp,
  2277.        'quit: NOT SAVED!  save first? y=yes, N=no, e=edit some more ');
  2278.       keylist := 'yNe';
  2279.     end
  2280.   else
  2281.     begin
  2282.       xwritexy(1,lpp,'quit?  y=yes, n=no ');
  2283.       keylist := 'yn';
  2284.     end;
  2285.  
  2286.   repeat
  2287.     c := xreadkey;
  2288.   until pos(c,keylist)<>0;
  2289.  
  2290.   if changed then
  2291.     if c='y' then
  2292.       begin
  2293.         xwrites('yes: quit+save');
  2294.         writefile(filename);
  2295.         quitout := true;
  2296.       end
  2297.     else if c='e' then
  2298.       begin
  2299.         setstatusline('');
  2300.       end
  2301.     else
  2302.       begin
  2303.         xwrites('no: quit, NO save');
  2304.         quitout := true;
  2305.       end
  2306.   else
  2307.     if c='y' then
  2308.       begin
  2309.         xwrites('yes: quit (no changes)');
  2310.         quitout := true;
  2311.       end
  2312.     else
  2313.       begin
  2314.         setstatusline('');
  2315.       end
  2316. end;
  2317.  
  2318. procedure coloncommands;
  2319.  
  2320. var
  2321.   cmdverb: string;
  2322.   cmdobj: string;
  2323.  
  2324. begin
  2325.   setstatusline('<:>');
  2326.  
  2327.   xgotoxy(2,lpp);
  2328.   xreadlns(cmdline,cols-2,yespreserve);
  2329.  
  2330.   xgotoxy(1,lpp);
  2331.  
  2332.   cmdline := lower(trim(ltrim(cmdline)));
  2333.  
  2334. {first, assume no arguments}
  2335.  
  2336.   if cmdline='' then donothing
  2337.  
  2338.   else if cmdline='h' then bighelp
  2339.   else if cmdline='help' then bighelp
  2340.  
  2341.   else if cmdline='f' then displayfileinfo
  2342.   else if cmdline='file' then displayfileinfo
  2343.  
  2344.   else if cmdline='q' then quit
  2345.   else if cmdline='quit' then quit
  2346.  
  2347.   else if cmdline='q!' then quitout := true
  2348.   else if cmdline='quit!' then quitout := true
  2349.  
  2350.   else if cmdline='w' then writefile(filename)
  2351.   else if cmdline='write' then writefile(filename)
  2352.  
  2353.   else if cmdline='e' then mayberereadfile
  2354.   else if cmdline='edit' then mayberereadfile
  2355.  
  2356.   else if cmdline='e!' then rereadfile
  2357.   else if cmdline='edit!' then rereadfile
  2358.  
  2359.   else if cmdline='x' then
  2360.     begin
  2361.       maybewritefile(filename);
  2362.       quitout := true;
  2363.     end
  2364.  
  2365.   else if atoi(cmdline)>0 then
  2366.     begin
  2367.       counter := atoi(cmdline);
  2368.       gotoline;
  2369.     end
  2370.  
  2371. {after here are commands which take filename arguments}
  2372.  
  2373.   else {if cmdline<>'' then} {could put it here, but removes symmetry above}
  2374.     begin
  2375.       cmdobj := unslash(cmdline);
  2376.       cmdverb := chopfirstw(cmdobj);
  2377.  
  2378.       cmdobj := fixfn(cmdobj);
  2379.  
  2380.       if cmdobj='' then
  2381.         setstatusline('<Unknown command>')
  2382.       else if not trusted and (directory='') then
  2383.         setstatusline('<Would require --trusted or --directory>')
  2384.       else
  2385.         begin
  2386.  
  2387. {note that mayuse changes cmdobj to full directory/path if need be}
  2388.  
  2389.           if not mayuse(cmdobj) then
  2390.             begin
  2391.               if trusted then
  2392.                 setstatusline('<illegal filename>')
  2393.               else
  2394.                 setstatusline('<illegal filename without --trusted>')
  2395.             end
  2396.           else if (cmdverb='r') or (cmdverb='read') then
  2397.             insertfile(cmdobj)
  2398.           else if (cmdverb='w') or (cmdverb='write') then
  2399.             maybewritetofile(cmdobj)
  2400.           else if (cmdverb='w!') or (cmdverb='write!') then
  2401.             writetofile(cmdobj)
  2402.           else if (cmdverb='e') or (cmdverb='edit') then
  2403.             maybenewfile(cmdobj)
  2404.           else if (cmdverb='e!') or (cmdverb='edit!') then
  2405.             newfile(cmdobj)
  2406.           else
  2407.             setstatusline('<Unknown command>');
  2408.         end;
  2409.     end;
  2410.  
  2411.   restorecurs;
  2412. end;
  2413.  
  2414. procedure searchdirection(direction: integer);
  2415.  
  2416. var
  2417.   countup: integer;
  2418.   needrefresh: boolean;
  2419.  
  2420.   oldline: integer;
  2421.   newline: integer;
  2422.  
  2423.   newstr: string;
  2424.   newcol: integer;
  2425.  
  2426.   found: boolean;
  2427.   wrapped: boolean;
  2428.  
  2429. begin
  2430. {$ifdef debug}
  2431.   if (direction<>1) and (direction<>-1) then
  2432.     debugdie('direction='+itoa(direction));
  2433. {$endif}
  2434.  
  2435.   if searchstring='' then
  2436.     setstatusline('<No previous search string>')
  2437.   else
  2438.     begin
  2439.       needrefresh := false;
  2440.  
  2441.       setstatusline('/');
  2442.  
  2443.       found := false;
  2444.       wrapped := false;
  2445.  
  2446.       for countup := 1 to usecounter do
  2447.         begin
  2448.           if direction=1 then
  2449.             begin
  2450.               newstr := lower(copy(currptr^.str,currcol+1,255));
  2451.               newcol := pos(searchstring,newstr);
  2452.               if newcol<>0 then
  2453.                 newcol := currcol+newcol;
  2454.             end
  2455.           else
  2456.             begin
  2457.               newstr :=
  2458.                lower(copy(currptr^.str,1,currcol-1+length(searchstring)-1));
  2459.               newcol := rpos(searchstring,newstr);
  2460.             end;
  2461.  
  2462.           if newcol<>0 then
  2463.             begin
  2464.               setcurrkeepcol(newcol);
  2465.               found := true;
  2466.             end
  2467.           else
  2468.             begin
  2469.               oldline := currline;
  2470.               found := false;
  2471.  
  2472.               repeat
  2473.                 newline := currline+direction;
  2474.                 if (newline<1) or (newline>numlines) then
  2475.                   begin
  2476.                     wrapped := true;
  2477.                     if newline<1 then
  2478.                       setcurrlineptr(numlines)
  2479.                     else
  2480.                       setcurrlineptr(1);
  2481.                   end
  2482.                 else
  2483.                   setcurrlineptr(newline);
  2484.  
  2485.                 if direction=1 then
  2486.                   newcol := pos(searchstring,lower(currptr^.str))
  2487.                 else
  2488.                   newcol := rpos(searchstring,lower(currptr^.str));
  2489.  
  2490.                 if newcol<>0 then
  2491.                   begin
  2492.                     found := true;
  2493.                     setcurrkeepcol(newcol);
  2494.                   end;
  2495.               until found or (oldline=currline);
  2496.  
  2497.               if offscreen(currline) then
  2498.                 begin
  2499.                   if direction=1 then
  2500.                     topline := max(1,currline-2)
  2501.                   else
  2502.                     topline := min(numlines-editinglpp+1,currline+2);
  2503.                   needrefresh := true;
  2504.                 end;
  2505.             end;
  2506.         end;
  2507.  
  2508.       restorecurs;
  2509.  
  2510.       if needrefresh then
  2511.         refreshall;
  2512.  
  2513.       if wrapped and found then
  2514.         setstatusline('(wrap)');
  2515.  
  2516.       if not found then
  2517.         setstatusline('<Pattern not found>');
  2518.     end;
  2519. end;
  2520.  
  2521. procedure searchnext;
  2522.  
  2523. begin
  2524.   searchdirection(1);
  2525. end;
  2526.  
  2527. procedure searchprevious;
  2528.  
  2529. begin
  2530.   searchdirection(-1);
  2531. end;
  2532.  
  2533. procedure slash;
  2534.  
  2535. begin
  2536.   setstatusline('</>');
  2537.  
  2538.   xgotoxy(2,lpp);
  2539.   xreadlns(searchstring,cols-2,yespreserve);
  2540.  
  2541.   searchstring := lower(searchstring);
  2542.  
  2543.   searchnext;
  2544. end;
  2545.  
  2546. procedure editfile;
  2547.  
  2548. var
  2549.   cmd: char;
  2550.  
  2551. begin
  2552.   bufferedstring := '';
  2553.  
  2554.   {no need for refresh here -- readfile already did it}
  2555.  
  2556.   undostring := '';
  2557.   undomaybestring := '';
  2558.   undoline := 0;
  2559.  
  2560.   alternatefilename := '';
  2561.  
  2562.   quitout := false;
  2563.   while not quitout do
  2564.     begin
  2565.       cmd := xreadkey;
  2566.  
  2567. {$ifdef debug}
  2568.       if length(history)>60 then
  2569.         history := copy(history,2,255)+cmd
  2570.       else
  2571.         history := history+cmd;
  2572.  
  2573.       if debug then
  2574.         begin
  2575.           gotoxy(40,10);write(' ---------------------- ');
  2576.           gotoxy(40,11);write('|                      |');
  2577.           gotoxy(40,12);write('|                      |');
  2578.           gotoxy(40,13);write('|                      |');
  2579.           gotoxy(40,14);write(' ---------------------- ');
  2580.           gotoxy(42,11);
  2581.           if (ord(cmd)<32) or (ord(cmd)>126) then
  2582.             writeln('got key# ',ord(cmd))
  2583.           else
  2584.             writeln('got key: ',cmd,' ',ord(cmd));
  2585.           gotoxy(42,12);
  2586.           writeln('old currline=',currline);
  2587.           gotoxy(42,13);
  2588.           writeln('old maxavail=',maxavail);
  2589.           restorecurs;
  2590.         end;
  2591. {$endif}
  2592.  
  2593.       case cmd of
  2594.         '?': help;
  2595.  
  2596.         'z': bighelp;
  2597.  
  2598.         'u': undo;
  2599.  
  2600.         'j': downaline;
  2601.         ^N : downaline;
  2602.         ^J : downaline;
  2603.         ^M : begin downaline; gofirstnonblankcol; end;
  2604.         '+': begin downaline; gofirstnonblankcol; end;
  2605.  
  2606.         'k': upaline;
  2607.         ^P : upaline;
  2608.         ^K : upaline;
  2609.         '-': begin upaline; gofirstnonblankcol; end;
  2610.  
  2611.         'l': rightachar;
  2612.         ' ': rightachar;
  2613.         ^U : rightachar;  { Apple ][ forever :-) }
  2614.  
  2615.         'h': leftachar;
  2616.         ^H : leftachar;
  2617.        #127: leftachar;
  2618.  
  2619.         ^L : refreshall;
  2620.  
  2621.         'x': delchar;
  2622.         'X': delcharleft;
  2623.  
  2624.         'i': insert;
  2625.         'I': begin gofirstcol; insert; end;  {vi has gofirstnonblank, alas}
  2626.         'a': append;
  2627.         'A': begin golastcol; append; end;
  2628.  
  2629.         's': split;
  2630.         'c': combine;
  2631.         'J': combine;
  2632.  
  2633.         'o': openbelow;
  2634.         'O': openabove;
  2635.  
  2636.         'p': pasteafter;
  2637.         'P': pastebefore;
  2638.  
  2639.         'D': deleteline;
  2640.  
  2641.         'Y': yankline;
  2642.  
  2643.         'G': gotoline;
  2644.  
  2645.         ^F : goforwardpg;
  2646.         '>': goforwardpg;
  2647.         ^B : gobackpg;
  2648.         '<': gobackpg;
  2649.  
  2650.         'H': gohighline;
  2651.         'M': gomidline;
  2652.         'L': golowline;
  2653.  
  2654.         'w': writefile(filename);
  2655.         ^R : mayberereadfile;
  2656.  
  2657.         ^G : displayfileinfo;
  2658.  
  2659.         ^E : scrollup;
  2660.         ^Y : scrolldown;
  2661.  
  2662.         'r': replace;
  2663.         'R': replacemuch;
  2664.         '~': changecase;
  2665.  
  2666.         ':': coloncommands;
  2667.         '/': slash;
  2668.         'n': searchnext;
  2669.         'N': searchprevious;
  2670.  
  2671.         '|': gotocol;
  2672.         '$': golastcol;
  2673.         '^': gofirstnonblankcol;
  2674.  
  2675.         '0': if counter=0 then gofirstcol else addtocounter(0);
  2676.         '1': addtocounter(1);
  2677.         '2': addtocounter(2);
  2678.         '3': addtocounter(3);
  2679.         '4': addtocounter(4);
  2680.         '5': addtocounter(5);
  2681.         '6': addtocounter(6);
  2682.         '7': addtocounter(7);
  2683.         '8': addtocounter(8);
  2684.         '9': addtocounter(9);
  2685.  
  2686. {$ifdef debug}
  2687.         ^A : debug := not debug;
  2688.         ^Q : if debug then debugdie('control-Q');
  2689.  
  2690.         '!':
  2691.           begin
  2692.             gotoxy(40,2);write(' -------------------------- ');
  2693.             gotoxy(40,3);write('|                          |');
  2694.             gotoxy(40,4);write('|                          |');
  2695.             gotoxy(40,5);write('|                          |');
  2696.             gotoxy(40,6);write('|                          |');
  2697.             gotoxy(40,7);write('|                          |');
  2698.             gotoxy(40,8);write('|                          |');
  2699.             gotoxy(40,9);write(' -------------------------- ');
  2700.             gotoxy(42,3);write('topline=',topline);
  2701.             gotoxy(42,4);write('currline=',currline);
  2702.             gotoxy(42,5);write('currcol=',currcol);
  2703.             gotoxy(42,6);write('length=',currlength);
  2704.             gotoxy(42,7);write('str=',copy(currptr^.str,1,20));
  2705.             gotoxy(42,8);write('seq=',currptr^.seq);
  2706.             restorecurs;
  2707.           end;
  2708. {$endif}
  2709.  
  2710.         'q': quit;
  2711.         'Q': quit;
  2712.       end;
  2713.  
  2714. {$ifdef debug}
  2715.       if debug then
  2716.         begin
  2717.           gotoxy(40,16);write(' ---------------------- ');
  2718.           gotoxy(40,17);write('|                      |');
  2719.           gotoxy(40,18);write('|                      |');
  2720.           gotoxy(40,19);write('|                      |');
  2721.           gotoxy(40,20);write(' ---------------------- ');
  2722.           gotoxy(42,17);
  2723.           if (ord(cmd)<32) or (ord(cmd)>126) then
  2724.             writeln('got key# ',ord(cmd))
  2725.           else
  2726.             writeln('got key: ',cmd,' ',ord(cmd));
  2727.           gotoxy(42,18);
  2728.           writeln('currline=',currline);
  2729.           gotoxy(42,19);
  2730.           writeln('maxavail=',maxavail);
  2731.           restorecurs;
  2732.  
  2733.           if quitout then
  2734.             gotoxy(1,lpp);
  2735.         end;
  2736. {$endif}
  2737.  
  2738.     end;
  2739. end;
  2740.  
  2741. procedure initialize;
  2742.  
  2743. var
  2744.   currparami: integer;
  2745.   currparams: string;
  2746.  
  2747.   colors: string;
  2748.  
  2749.   foundtrusted: boolean;
  2750.  
  2751. begin
  2752.   foundtrusted := false;
  2753.  
  2754.   shadow := 0;
  2755.  
  2756. {$ifdef debug}
  2757.   debug := false;
  2758.   highseq := 0;
  2759.   history := '';
  2760. {$endif}
  2761.  
  2762. {$ifdef debug}
  2763.   shadow := 1;
  2764. {$endif}
  2765.  
  2766.   alwayshelp := false;
  2767.  
  2768.   console := true;
  2769.   port := -1;
  2770.   minutestorun := maxint;
  2771.   idleminutes := 5;
  2772.   trusted := true;
  2773.   directory := '';
  2774.  
  2775.   oldtextattr := textattr;
  2776.  
  2777.   colors := getenv('COLORS');
  2778.   if colors='' then
  2779.     colors := getenv('COLOURS');
  2780.   if colors='' then
  2781.     colors := '7 15';
  2782.  
  2783.   lpp := 25;
  2784.   cols := 80;
  2785.  
  2786.   cmdline := '';
  2787.   searchstring := '';
  2788.  
  2789.   if paramcount=0 then
  2790.     usage;
  2791.  
  2792. {$ifdef debug}
  2793.   writeln('paramcount: ',paramcount);
  2794.   if paramcount>0 then writeln('paramstr(1): ',paramstr(1));
  2795.   if paramcount>1 then writeln('paramstr(2): ',paramstr(2));
  2796.   if paramcount>2 then writeln('paramstr(3): ',paramstr(3));
  2797.   if paramcount>3 then writeln('paramstr(4): ',paramstr(4));
  2798.   if paramcount>4 then writeln('paramstr(5): ',paramstr(5));
  2799. {$endif}
  2800.  
  2801.   currparami := 1;
  2802.   currparams := paramstr(currparami);
  2803.   while (currparami<=paramcount) and (copy(currparams,1,1)='-') do
  2804.     begin
  2805.       if currparams='-?' then
  2806.         usage
  2807.       else if (currparams='-h') or (currparams='--help') then
  2808.         begin
  2809.           alwayshelp := true;
  2810.         end
  2811.       else if (currparams='-m') or (currparams='--minutes') then
  2812.         begin
  2813.           if currparami=paramcount then
  2814.             usage;
  2815.           inc(currparami);
  2816.           currparams := paramstr(currparami);
  2817.           minutestorun := atoi(currparams);
  2818.         end
  2819.       else if (currparams='-d') or (currparams='--dir') then
  2820.         begin
  2821.           if currparami=paramcount then
  2822.             usage;
  2823.           inc(currparami);
  2824.           currparams := paramstr(currparami);
  2825.           directory := unslash(currparams);
  2826.           if right(directory,1)='\' then
  2827.             directory := copy(directory,1,length(directory)-1);
  2828.         end
  2829.       else if (currparams='-p') or (currparams='--port') then
  2830.         begin
  2831.           if currparami=paramcount then
  2832.             usage;
  2833.           inc(currparami);
  2834.           currparams := paramstr(currparami);
  2835.           port := atoi(currparams)-1;
  2836.           console := false;
  2837.           trusted := false;
  2838.         end
  2839.       else if (currparams='-f') or (currparams='--fossil-port') then
  2840.         begin
  2841.           if currparami=paramcount then
  2842.             usage;
  2843.           inc(currparami);
  2844.           currparams := paramstr(currparami);
  2845.           port := atoi(currparams);
  2846.           console := false;
  2847.           trusted := false;
  2848.         end
  2849.       else if (currparams='-t') or (currparams='--trusted') then
  2850.         begin
  2851.           foundtrusted := true;
  2852.         end
  2853.       else if (currparams='-l') or (currparams='--lines') then
  2854.         begin
  2855.           if currparami=paramcount then
  2856.             usage;
  2857.           inc(currparami);
  2858.           currparams := paramstr(currparami);
  2859.           lpp := atoi(currparams);
  2860.           lpp := max(minlpp,min(lpp,maxlpp));
  2861.         end
  2862.       else if (currparams='-c') or (currparams='--columns') then
  2863.         begin
  2864.           if currparami=paramcount then
  2865.             usage;
  2866.           inc(currparami);
  2867.           currparams := paramstr(currparami);
  2868.           cols := atoi(currparams);
  2869.           cols := max(mincols,min(cols,maxcols));
  2870.         end
  2871.       else if (currparams='--colors') or (currparams='--colours') then
  2872.         begin
  2873.           if currparami=paramcount then
  2874.             usage;
  2875.           inc(currparami);
  2876.           currparams := paramstr(currparami);
  2877.           colors := currparams;
  2878.         end
  2879.       else
  2880.         begin
  2881.           writeln('unknown parameter: ',currparams);
  2882.           usage;
  2883.         end;
  2884.  
  2885.       inc(currparami);
  2886.       if currparami<=paramcount then
  2887.         currparams := paramstr(currparami);
  2888.     end;
  2889.  
  2890.   if currparami<>paramcount then
  2891.     begin
  2892.       writeln('filename is required');
  2893.       usage;
  2894.     end;
  2895.  
  2896.   filename := paramstr(currparami);
  2897.  
  2898.   if not console then
  2899.     begin
  2900.       if (port<>0) and (port<>1) and (port<>2) and (port<>3) then
  2901.         begin
  2902.           writeln('must use port 1-4 (fossil-port 0-3)');
  2903.           usage;
  2904.         end;
  2905.     end;
  2906.  
  2907.   filename := unslash(filename);
  2908.  
  2909.   if foundtrusted then
  2910.     trusted := true;
  2911.  
  2912.   minstart := mitoday;
  2913.   minlastinput := mitoday;
  2914.  
  2915.   editinglpp := lpp-2;
  2916.  
  2917.   if alwayshelp then
  2918.     editinglpp := editinglpp-3;  {two lines of help, one blank line}
  2919.  
  2920. {with tpascal it's a pain to pass , on the command-line?!}
  2921.   colors := crepl(uncomma(ununderscore(colors)),'/',' ');
  2922.   if colors<>'' then
  2923.     begin
  2924.       lowcolor := atoi(chopfirstw(colors));
  2925.       highcolor := atoi(getfirstw(colors));
  2926.     end;
  2927.  
  2928.   if (lowcolor mod 16)=(highcolor mod 16) then
  2929.     if (lowcolor mod 16)=7 then
  2930.       highcolor := 15
  2931.     else
  2932.       lowcolor := 7;
  2933.  
  2934.   xlowvideo;
  2935.  
  2936.   head := @afterhead;
  2937.   unused := nil;
  2938.  
  2939.   readfileinit;
  2940. end;
  2941.  
  2942. begin
  2943.   initialize;
  2944.  
  2945. {$ifdef debug}
  2946. {$ifdef smallmemory}
  2947.   exec('c:\usr\bin\freem.exe','');
  2948.   xwritess(editorname,': freem: doserror=');
  2949.   xwritei(doserror);
  2950.   xwriteln;
  2951. {$endif}
  2952. {$endif}
  2953.  
  2954.   if fexists(filename) and not isasciifile(filename) then
  2955.     begin
  2956.       xwritelnss(editorname,' can only be used on ASCII files');
  2957.       usage;
  2958.     end;
  2959.  
  2960.   readfile;
  2961.   editfile;
  2962.  
  2963.   restorecolors;
  2964. end.